package es.uned.etsii.si3.taller.servlets;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.opensymphony.xwork2.ActionSupport;

import es.uned.etsii.si3.taller.Cliente;
import es.uned.etsii.si3.taller.FactoriaDAO;
import es.uned.etsii.si3.taller.FactoriaFunciones;
import es.uned.etsii.si3.taller.Provincia;
import es.uned.etsii.si3.taller.Usuario;
import es.uned.etsii.si3.taller.misc.ProporcionaFuncionalidad;

public class BusquedaYBajaClientes extends ActionSupport {
	private static final long serialVersionUID = 1L;

	private Usuario usuario = null;
	private Cliente cliente = null;
	
	private String nombreUsuario   = "";
	private String nombre    = "";
	private String apellidos = "";
	private String dni       = "";
	private String telefono  = "";
	private List<Cliente> listaClientes;
	private List<Integer> clientesEscogidos;
	private List<Baja> listaBajas;
	private List<Provincia> listaProvincias;
	
	public class Baja {
		private String cliente;
		private String usuario;
		private boolean usuarioDesactivado;
		
		public Baja() {
			setUsuarioDesactivado(false);
			setUsuario("USUARIO DESCONOCIDO");
		}
		
		public String getCliente() {
			return cliente;
		}
		
		public String getUsuario() {
			return usuario;
		}
		
		public void setCliente(String cl) {
			cliente = cl;
		}
		
		public void setUsuario(String us) {
			usuario = us;
		}
		
		public boolean getUsuarioDesactivado() {
			return usuarioDesactivado;
		}
		
		public void setUsuarioDesactivado(boolean status) {
			usuarioDesactivado = status;
		}
	}

	// Getters / Setters
	
	/* BEGIN - getters para ir al formularioCliente */
	public boolean getEsClienteNuevo() {
		return false;
	}
	
	public Usuario getUsuario() {
		return usuario;
	}
	
	public Cliente getCliente() {
		return cliente;
	}
	
	public List<Provincia> getListaProvincias() {
		return listaProvincias;
	}
	
	public int getProvinciaParaCliente() {
		return cliente.getProvincia().getId();
	}
	/* END - getters para ir al formularioCliente */

	public String getNombreUsuario() {
		return nombreUsuario;
	}
	
	public String getNombre() {
		return nombre;
	}

	public String getApellidos() { 
		return apellidos; 
	}

	public String getDni() {
		return dni;
	}
	
	public String getTelefono() {
		return telefono;
	}
	
	public List<Cliente> getListaClientes() {
		return listaClientes;
	}
	
	public List<Baja> getListaBajas() {
		return listaBajas;
	}
	
	public void setNombreUsuario(String nombreUsuario) {
		if (nombreUsuario != null)
			this.nombreUsuario = nombreUsuario.trim();
	}
	
	public void setNombre(String nombre) {
		if (nombre != null)
			this.nombre = nombre.trim();
	}
	
	public void setApellidos(String apellidos) {
		if (apellidos != null)
			this.apellidos = apellidos.trim();
	}
	
	public void setDni(String dni) {
		if (dni != null)
			this.dni = dni.trim();
	}
	
	public void setTelefono(String telefono) {
		if (telefono != null)
			this.telefono = telefono.trim();
	}
	
	public void setClientesEscogidos(List<Integer> listaEscogidos) {
		clientesEscogidos = listaEscogidos;
	}
	
	private String hacerLike(String valor) {
		return "%" + valor + "%";
	}
	
	/**
	 * Obtiene la lista de usuarios coincidentes con la búsqueda dada
	 */
	@Override
	public String execute() {
		if (!hayCondiciones()) {
			addActionMessage("No se puede hacer una consulta sin introducir alguna restricción");
			return SUCCESS;
		}
		
		try {
			boolean doOr = false;

			QueryBuilder<Cliente, Integer> clienteQb = FactoriaDAO.getQueryBuilder(Cliente.class);
			
			// Esto es para asegurar que se escogen sólo usuarios activos 
			{
				QueryBuilder<Usuario, Integer> usuarioQb = FactoriaDAO.getQueryBuilder(Usuario.class);
				usuarioQb.where().eq(Usuario.ACTIVO_FIELD_NAME, true);
				clienteQb.join(usuarioQb);
			}

			Where<Cliente, Integer> whereCliente = clienteQb.where();

			if (tieneLongitud(getNombreUsuario())) {
				QueryBuilder<Usuario, Integer> usuarioQb = FactoriaDAO.getQueryBuilder(Usuario.class);
				usuarioQb.selectColumns(Usuario.ID_FIELD_NAME);
				usuarioQb.where().like(Usuario.USUARIO_FIELD_NAME, hacerLike(getNombreUsuario()))
								 .and()
								 .eq(Usuario.ACTIVO_FIELD_NAME, true);

				whereCliente.in(Cliente.ID_USUARIO_FIELD_NAME, usuarioQb);
				doOr = true;
			}

			if (tieneLongitud(getNombre())) {
				if (doOr) whereCliente.or();

				whereCliente.like(Cliente.NOMBRE_FIELD_NAME, hacerLike(getNombre()));
				doOr = true;
			}

			if (tieneLongitud(getApellidos())) {
				if (doOr) whereCliente.or();

				whereCliente.like(Cliente.APELLIDOS_FIELD_NAME, hacerLike(getApellidos()));
				doOr = true;
			}

			if (tieneLongitud(getDni())) {
				if (doOr) whereCliente.or();

				whereCliente.like(Cliente.DNI_FIELD_NAME, hacerLike(getDni()));
				doOr = true;
			}

			if (tieneLongitud(getTelefono())) {
				if (doOr) whereCliente.or();

				whereCliente.like(Cliente.TELEFONO_FIELD_NAME, hacerLike(getTelefono()));
			}
			

			listaClientes = clienteQb.query();

			if (listaClientes.size() == 0)
				addActionMessage("No se encontraron usuarios que coincidan");
		} catch (SQLException e) {
			addActionError("Al intentar hacer la búsqueda: " + e.toString());
		}
		return SUCCESS;
	}

	// Comprobación rápida para saber si queremos hacer una consulta, o no
	private boolean tieneLongitud(String t) { if (t.length() > 0) return true; return false; }

	private boolean hayCondiciones() {
		if (tieneLongitud(getNombreUsuario()) || 
				tieneLongitud(getNombre()) || 
				tieneLongitud(getApellidos()) ||
				tieneLongitud(getDni()) ||
				tieneLongitud(getTelefono()))
			return true;
		return false;
	}
	
	private List<Cliente> clientesPorId(List<Integer> listaIds) {
		List<Cliente> lista = new ArrayList<Cliente>();
		try {
			for(Integer indice: listaIds) {
				lista.add(FactoriaDAO.recuperar(Cliente.class, indice.intValue()));
			}
		} catch (SQLException e) {
			addActionError("No se pudo recuperar la lista de clientes: " + e.toString());
			lista = null;
		}
		
		return lista;
	}
	
	/**
	 * Permite modificar el cliente
	 * @return actionerror
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_MODIFICAR_CLIENTE)
	public String modificar() {
		if ((clientesEscogidos == null) || (clientesEscogidos.size() == 0)) {
			addActionError("No se ha escogido ningún cliente a eliminar");
			return INPUT;
		}
		
		listaClientes = clientesPorId(clientesEscogidos);
		
		if (listaClientes.size() > 1) {
			addActionError("Sólo puede escoger un cliente para modificar");
			return INPUT;
		}
		
		cliente = listaClientes.get(0);
		usuario = cliente.getUsuario();
		if (usuario == null) {
			addActionError("No se pudo recuperar el usuario del cliente " + cliente.getId() + " con nombre " + cliente.getNombre());
			return INPUT;
		}
		try {
			usuario.refresh();
		} catch (SQLException e) {
			addActionError("No se pudo recuperar el usuario correspondiente al cliente: " + e.toString());
			return INPUT;
		}
		
		List<Provincia> lista;
		try {
			lista = FactoriaDAO.getDao(Provincia.class)
				       .queryBuilder()
				       .orderBy(Provincia.NOMBRE_FIELD_NAME, true)
				       .query();
			Provincia nula = new Provincia();
			nula.setNombre("-----------");
			lista.add(0, nula);
			listaProvincias = lista;
		} catch (SQLException e) {
			addActionError("Error accediendo a la base de datos: " + e.toString());
			return INPUT;
		}

		
		return SUCCESS;
	}
	
	/**
	 * Solicita confirmación de la baja
	 * @return actionerror
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_BAJA_CLIENTE)
	public String confirmarBaja() {
		if ((clientesEscogidos == null) || (clientesEscogidos.size() == 0)) {
			addActionError("No se ha escogido ningún cliente a eliminar");
			return INPUT;
		}
		
		listaClientes = clientesPorId(clientesEscogidos);
		
		return SUCCESS;
	}

	/**
	 * Da de baja un cliente
	 * @return actionerror
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_BAJA_CLIENTE)
	public String darDeBaja() {
		if ((clientesEscogidos == null) || (clientesEscogidos.size() == 0)) {
			addActionError("No se ha escogido ningún cliente a eliminar");
			return INPUT;
		}
		
		listaBajas = new ArrayList<Baja>();
		
		for(Cliente cliente: clientesPorId(clientesEscogidos)) {
			Baja baja = new Baja();
			
			listaBajas.add(baja);
			baja.setCliente(cliente.getNombre());
			try {
				Usuario usuario = cliente.getUsuario();
				usuario.update();
				
				baja.setUsuario(usuario.getUsuario());
				try {
					usuario.desactivar();
					baja.setUsuarioDesactivado(true);
				} catch (SQLException e) {
					addActionError("Error al intentar desactivar al usuario {" + baja.getUsuario() +
							"}, del que depende el cliente {" + baja.getCliente() + "}.");
				}
			} catch (SQLException e) {
				addActionError("Error al intentar recuperar el usuario asociado al cliente: " + baja.getCliente());
			}
		}
		
		if (!hasActionErrors())
			addActionMessage("Dados de baja los clientes con éxito");
		
		return SUCCESS;
	}
}